package org.api.free.service.ocr;

import lombok.extern.slf4j.Slf4j;
import net.sourceforge.tess4j.Tesseract;
import org.api.free.config.TessertactConfig;
import org.api.free.po.PreprocessingOptions;
import org.bytedeco.javacpp.Loader;
import org.bytedeco.opencv.opencv_java;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

@Service
@Slf4j
public class OcrServiceHight {
    static {
        Loader.load(opencv_java.class);
    }

    Tesseract tesseract = new Tesseract();
    @Resource
    private TessertactConfig tc;

    // 主处理函数
    public String recognizeText(MultipartFile file, PreprocessingOptions options) throws Exception {
        File convFile = null;
        Mat processedImage = null;
        try {
            convFile = convertMultipartFile(file);
            processedImage = preprocessImageOpenCV(convFile.getAbsolutePath(), options);
            Imgcodecs.imwrite(tc.getTmpdir() + "transfer_" + file.getOriginalFilename(), processedImage);
            tesseract.setDatapath(tc.getDatadir());
            tesseract.setLanguage("eng+chi_sim");
            return tesseract.doOCR(matToBufferedImage(processedImage));
        } finally {
            if (convFile != null && convFile.exists()) {
                try {
                    Files.deleteIfExists(convFile.toPath());
                } catch (IOException e) {
                    log.warn("Failed to delete temporary file: {}", convFile.getAbsolutePath(), e);
                }
            }
            if (processedImage != null) {
                processedImage.release();
            }
        }
    }

    // 转换 MultipartFile 为 File
    private File convertMultipartFile(MultipartFile file) throws IOException {
        Path tempDir = Paths.get(tc.getTmpdir());
        if (!Files.exists(tempDir)) {
            Files.createDirectories(tempDir);
        }
        File convFile = new File(tc.getTmpdir() + file.getOriginalFilename());
        file.transferTo(convFile);
        return convFile;
    }

    // 使用 OpenCV 进行图片预处理
    private Mat preprocessImageOpenCV(String imagePath, PreprocessingOptions options) {
        Mat source = null;
        Mat grayImage = null;
        Mat contrastImage = null;
        Mat binaryImage = null;
        Mat denoisedImage = null;
        Mat scaledImage = null;
        Mat currentImage = null;

        try {
            source = Imgcodecs.imread(imagePath);
            currentImage = source;

            // 1. 灰度化处理（如果启用）
            if (options.getGrayscale() != null && options.getGrayscale()) {
                grayImage = new Mat();
                Imgproc.cvtColor(source, grayImage, Imgproc.COLOR_BGR2GRAY);
                currentImage = grayImage;
            }

            // 2. 对比度增强（如果启用且有对比度值）
            if (options.getContrast() != null && options.getContrast() != 0) {
                double contrastFactor = 1.0 + (options.getContrast() / 100.0);
                contrastImage = enhanceContrastManual(currentImage, contrastFactor);
                if (currentImage != source && currentImage != grayImage) {
                    currentImage.release();
                }
                currentImage = contrastImage;
            }

            // 3. 二值化（阈值处理）（如果启用）
            if (options.getBinarization() != null && options.getBinarization()) {
                binaryImage = new Mat();
                Imgproc.threshold(currentImage, binaryImage, 180, 255, Imgproc.THRESH_BINARY);
                if (currentImage != source && currentImage != grayImage && currentImage != contrastImage) {
                    currentImage.release();
                }
                currentImage = binaryImage;
            }

            // 4. 降噪处理（中值滤波）（如果启用）
            if (options.getDenoising() != null && options.getDenoising()) {
                denoisedImage = new Mat();
                Imgproc.medianBlur(currentImage, denoisedImage, 3);
                if (currentImage != source && currentImage != grayImage && currentImage != contrastImage && currentImage != binaryImage) {
                    currentImage.release();
                }
                currentImage = denoisedImage;
            }

            // 5. 提升分辨率（按比例缩放）（如果启用）
            if (options.getEnhanceResolution() != null && options.getEnhanceResolution()) {
                scaledImage = new Mat();
                double scaleFactor = 2.0;
                Imgproc.resize(currentImage, scaledImage, new Size(currentImage.cols() * scaleFactor, currentImage.rows() * scaleFactor));
                if (currentImage != source && currentImage != grayImage && currentImage != contrastImage && currentImage != binaryImage && currentImage != denoisedImage) {
                    currentImage.release();
                }
                currentImage = scaledImage;
            }

            // 6. 自动旋转校正（基于Hough变换）
            Mat deskewedImage = deskewImageOpenCV(currentImage);
            if (deskewedImage != currentImage) {
                if (currentImage != source && currentImage != grayImage && currentImage != contrastImage && currentImage != binaryImage && currentImage != denoisedImage && currentImage != scaledImage) {
                    currentImage.release();
                }
                return deskewedImage;
            }
            Mat result = deskewedImage.clone();
            return result;
        } finally {
            if (source != null && !source.empty()) {
                source.release();
            }
            if (grayImage != null && !grayImage.empty() && grayImage != currentImage) {
                grayImage.release();
            }
            if (contrastImage != null && !contrastImage.empty() && contrastImage != currentImage) {
                contrastImage.release();
            }
            if (binaryImage != null && !binaryImage.empty() && binaryImage != currentImage) {
                binaryImage.release();
            }
            if (denoisedImage != null && !denoisedImage.empty() && denoisedImage != currentImage) {
                denoisedImage.release();
            }
            if (scaledImage != null && !scaledImage.empty() && scaledImage != currentImage) {
                scaledImage.release();
            }
        }
    }

    // 使用 OpenCV 进行自动旋转校正
    private Mat deskewImageOpenCV(Mat source) {
        return source;
    }

    // 将 OpenCV 的 Mat 对象转换为 BufferedImage
    private BufferedImage matToBufferedImage(Mat mat) {
        int type = BufferedImage.TYPE_BYTE_GRAY;
        if (mat.channels() > 1) {
            type = BufferedImage.TYPE_3BYTE_BGR;
        }
        int bufferSize = Double.valueOf(mat.cols() * mat.rows() * mat.elemSize()).intValue();
        byte[] buffer = new byte[bufferSize];
        mat.get(0, 0, buffer);
        BufferedImage image = new BufferedImage(mat.cols(), mat.rows(), type);
        final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
        System.arraycopy(buffer, 0, targetPixels, 0, buffer.length);
        return image;
    }

    private Mat enhanceContrastManual(Mat source, double contrastFactor) {
        Mat enhanced = new Mat();
        Core.addWeighted(source, contrastFactor, source, 0, 0, enhanced);
        return enhanced;
    }
}
